package cn.caplike.demo.repository.java.concurrency.threadpool.demo;

import java.util.LinkedList;
import java.util.List;

/**
 * 简介：线程池类，线程管理器：创建线程，执行任务，销毁线程，获取线程基本信息
 *
 * @author 李珂 2017年11月29日 上午9:40:27
 */
public class ThreadPool {
    private static int worker_num = 5; // 线程池中默认的线程个数为5
    private static volatile int finished_task = 0; // 处理的任务
    private static ThreadPool threadPool;
    private WorkThread[] workThreads; // 工作线程
    private List<Runnable> taskQueue = new LinkedList<Runnable>(); // 任务队列，作为一个缓冲，List线程不安全

    /**
     * 简介：创建具有默认线程个数的线程池
     *
     * @author 李珂 2017年11月29日 上午9:49:25
     */
    private ThreadPool() {
        this(5);
    }

    /**
     * 简介：创建线程池，worker_num为线程池中工作线程的个数
     *
     * @param num
     * @author 李珂 2017年11月29日 上午9:49:52
     */
    private ThreadPool(int num) {
        ThreadPool.worker_num = num;
        workThreads = new WorkThread[ThreadPool.worker_num];
        for (int i = 0; i < worker_num; i++) {
            workThreads[i] = new WorkThread();
            new Thread(workThreads[i]).start();
        }
    }

    /**
     * 简介：单例模式，获得一个默认线程个数的线程池
     *
     * @return
     * @author 李珂 2017年11月29日 上午10:01:22
     */
    public static ThreadPool getTheadPool() {
        return getThreadPool(ThreadPool.worker_num);
    }

    /**
     * 简介：单例模式，获得一个指定线程个数的线程池
     *
     * @param worker_num
     * @return
     * @author 李珂 2017年11月29日 上午10:09:29
     */
    public static ThreadPool getThreadPool(int worker_num) {
        if (worker_num <= 0)
            worker_num = ThreadPool.worker_num;
        if (threadPool == null)
            threadPool = new ThreadPool(ThreadPool.worker_num);
        return threadPool;
    }

    /**
     * 简介：执行任务<br>
     * 详细说明：其实只是把任务加入任务队列，什么时候执行有线程池管理器决定
     *
     * @param task
     * @author 李珂 2017年11月29日 上午10:11:29
     */
    public void execute(Runnable task) {
        synchronized (taskQueue) {
            taskQueue.add(task);
            taskQueue.notify();
        }
    }

    /**
     * 简介：批量执行任务<br>
     * 详细说明：其实只是把任务加入任务队列，什么时候执行有线程池管理器决定
     *
     * @param taskArr
     * @author 李珂 2017年11月29日 上午10:15:35
     */
    public void execute(Runnable[] taskArr) {
        synchronized (taskQueue) {
            for (Runnable task : taskArr) {
                taskQueue.add(task);
            }
            taskQueue.notify();
        }
    }

    /**
     * 简介：批量执行任务<br>
     * 详细说明：其实只是把任务加入任务队列，什么时候执行有线程池管理器决定
     *
     * @param taskArr
     * @author 李珂 2017年11月29日 上午10:15:35
     */
    public void execute(List<Runnable> taskArr) {
        synchronized (taskQueue) {
            for (Runnable task : taskArr) {
                taskQueue.add(task);
            }
            taskQueue.notify();
        }
    }

    /**
     * 简介：销毁线程池
     *
     * @author 李珂 2017年11月29日 上午10:17:22
     */
    public void destory() {
        while (!taskQueue.isEmpty()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        /* 停止工作线程 */
        for (int i = 0; i < worker_num; i++) {
            workThreads[i].stopWorker();
            workThreads[i] = null;
        }
        threadPool = null;
        taskQueue.clear();// 清空任务队列
    }

    /**
     * 简介：返回工作线程的个数
     *
     * @return
     * @author 李珂 2017年11月29日 上午11:26:57
     */
    public int getWorkerThreadNumber() {
        return worker_num;
    }

    /**
     * 简介：返回已完成任务的个数，这里的已完成是只出了任务队列的任务个数，可能该任务并没有实际执行完成
     *
     * @return
     * @author 李珂 2017年11月29日 上午11:29:16
     */
    public int getFinishedTasknumber() {
        return finished_task;
    }

    /**
     * 简介：返回任务队列的长度，即还没处理的任务个数
     *
     * @return
     * @author 李珂 2017年11月29日 上午11:29:05
     */
    public int getWaitTasknumber() {
        return taskQueue.size();
    }

    @Override
    public String toString() {
        return "WorkThread number:" + worker_num + "  finished task number:" + finished_task + "  wait task number:" + getWaitTasknumber();
    }

    /**
     * 简介：私有内部类，工作线程
     *
     * @author 李珂 2017年11月29日 上午9:42:41
     */
    private class WorkThread implements Runnable {
        private Boolean isRunning = true;

        /*
         * (non-Javadoc)
         *
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            Runnable r = null;
            while (isRunning) {
                synchronized (taskQueue) {
                    while (isRunning && taskQueue.isEmpty()) {
                        try {
                            taskQueue.wait(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if (!taskQueue.isEmpty()) {
                        r = taskQueue.remove(0); // 取出任务
                    }
                }
                if (r != null)
                    r.run();
                finished_task++;
                r = null;
            }
        }

        /**
         * 简介：停止工作，让该线程自然执行完run方法，自然结束
         *
         * @author 李珂 2017年11月29日 上午10:40:51
         */
        public void stopWorker() {
            isRunning = false;
        }
    }
}
